home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch05
/
dither.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-08
|
15KB
|
397 lines
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<fcntl.h>
#include<io.h>
#include<vsa.h>
#include<vsa_font.h>
#include<tiff.h>
#ifndef _MSC_VER
/*..... This is line for Borland C Only ! .....*/
extern unsigned _stklen = 13000;
#endif
void draw_dithered_pixel(int,int,unsigned char *,int);
int crack_rgb(unsigned char *,int *,int *,int *,float *,
float *,float *);
unsigned long read_tga_header(int,int *,int *,int *,int *);
void true_color_lut(void);
void vsa_get_input(char *);
void update_message(int,int,int,char *);
void clear_text_area(int,int,int,int);
void color_bar(int,int);
unsigned char dither[4][64]={
{
1 },
{
1, 3,
4, 2 },
{
1, 9, 3, 11,
13, 5, 15, 7,
4, 12, 2, 10,
16, 8, 14, 6 },
{
1, 33, 9, 41, 3, 35, 11, 43,
49, 17, 57, 25, 51, 19, 59, 27,
13, 45, 5, 37, 15, 47, 7, 39,
61, 29, 53, 21, 63, 31, 55, 23,
4, 36, 12, 44, 2, 34, 10, 42,
52, 20, 60, 28, 50, 18, 58, 26,
16, 48, 8, 40, 14, 46, 6, 38,
64, 32, 56, 24, 62, 30, 54, 22 },
};
/*......................... DITHER.C............. 5-29-94 .....*/
/* This program reads True Color (24 bit per pixel) TARGA */
/* images and converts them to 8 bit dithered screen images. */
/* It also writes out the dithered image as an 8 bit per pixel */
/* Palette Color TIFF image. */
/*.............................................................*/
void main(int argc, char *argv[])
{
char filename[80],text[100];
int i,j,size,width,height,type,file_handle,orient,vmode;
int r0,c0;
unsigned char rgb[3072];
if(argc > 1)
/*.............................................................*/
/* If specified, set requested video mode. */
/*.............................................................*/
{
sscanf(argv[1],"%x",&vmode);
if(vsa_init(vmode) != 0)
{
printf("Can't set Requested VESA video mode!\n");
printf("Is VESA BIOS Extension TSR loaded?\n");
return;
}
}
else
/*.............................................................*/
/* Otherwise set highest video resolution available. */
/*.............................................................*/
{
if(vsa_init(0x105) != 0) /* 1024 x 768 x 256 */
if(vsa_init(0x103) != 0) /* 800 x 600 x 256 */
if(vsa_init(0x101) != 0) /* 640 x 480 x 256 */
if(vsa_init(0x100) != 0) /* 640 x 400 x 256 */
{
printf("Can't set VESA video mode!\n");
printf("Is VESA BIOS Extension TSR loaded?\n");
return;
}
}
/*.............................................................*/
/* Set up the Palette as an 8 bit RGB (3,3,2) table. */
/* and draw color look up table. */
/*.............................................................*/
true_color_lut();
tf_set_prime_colors();
color_bar(0.125*XResolution,0.91*YResolution);
/*..........................................................................*/
/* Draw Frame around screen. */
/*..........................................................................*/
vsa_set_color(TF_Blue);
vsa_move_to(0,0);
vsa_rect(XResolution-1,YResolution-1);
/*..........................................................................*/
/* Set up text cursor mode and location. */
/*..........................................................................*/
vsa_set_text_cursor_mode(1);
r0 = 0.85*YCharResolution;
c0 = 0.5*XCharResolution - 17;
/*..........................................................................*/
/* Enter main loop which displays dithered images. */
/*..........................................................................*/
LOOP:
update_message(c0*XCharSize,r0*YCharSize,TF_Green,"Input TARGA Image Filename: ");
vsa_get_input(filename);
if(filename[0] == 0)
goto BAIL;
/*.............................................................*/
/* Get dither size and limit it to legal value of 1,2,4 or 8. */
/*.............................................................*/
update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Green,"Input Dither Size (1, 2, 4, or 8): ");
vsa_get_input(text);
sscanf(text,"%d",&size);
if(size == 3) size = 4; /* size limited to 1, 2, 4, or 8 */
if(size > 4) size = 8; /* size limited to 1, 2, 4, or 8 */
/*.............................................................*/
/* Open the TARGA file and get header info. */
/*.............................................................*/
if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
{
sprintf(text,"Can't find file %s",filename);
update_message(c0*XCharSize,r0*YCharSize,TF_Red,text);
update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Red,"");
getch();
goto LOOP;
}
update_message(c0*XCharSize,r0*YCharSize,TF_Violet,"Generating Dithered Image.");
update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Red,"");
read_tga_header(file_handle,&width,&height,&type,&orient);
/*.............................................................*/
/* Draw Frame around the new picture. */
/*.............................................................*/
vsa_set_color(TF_White);
vsa_move_to(2,2);
vsa_rect(width+3,height+3);
/*.............................................................*/
/* Read out pixels from TARGA file and plot on screen in */
/* top down or bottom up order depending on orientation. */
/*.............................................................*/
if(orient == 32)
for(j=0;j<height;j++)
{
read(file_handle,rgb,3*width);
for(i=0;i<width;i++)
draw_dithered_pixel(i+3,j+3,rgb+3*i,size);
}
else
for(j=height-1;j>=0;j--)
{
read(file_handle,rgb,3*width);
for(i=0;i<width;i++)
draw_dithered_pixel(i+3,j+3,rgb+3*i,size);
}
color_bar(0.125*XResolution,0.91*YResolution);
/*.............................................................*/
/* Close the image file and look for an ESC key to quit. */
/* Otherwise, save dithered image as an 8 bit TIFF called */
/* NEW.TIF and LOOP for experimentation with a different */
/* dither box size. */
/*.............................................................*/
close(file_handle);
update_message(c0*XCharSize,r0*YCharSize,TF_Red,
"ESC to quit, any other key to continue.");
update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Yellow,"");
if(getch() == 27)
goto BAIL;
update_message(c0*XCharSize,r0*YCharSize,TF_Blue,
"Saving image as NEW.TIF.");
tf_save_file(0,0,width-1,height-1,"new.tif");
goto LOOP; /*..... Oh No, a goto! .....*/
BAIL:
vsa_about();
getch();
vsa_set_svga_mode(0x3);
return; /*..... End main .....*/
}
/*.................... DRAW_DITHERED_PIXEL ....... 5-27-94 ....*/
/* This routine draws a dithered pixel at screen coordinate */
/* 'i,j' with 24 bit color equivalent passed in the 3 byte */
/* array 'rgb'. The dither pattern size is specified by 'size'*/
/* and can be 1, 2, 4, or 8. Note that the global 'dither' */
/* array must must be initialized before calling this routine. */
/*.............................................................*/
void draw_dithered_pixel(int i,int j,unsigned char *rgb,int size)
{
int n,m,q,r,red_lvl,grn_lvl,blu_lvl;
int color,red_boost,grn_boost,blu_boost;
float x,y,frl,fgl,fbl;
/*.............................................................*/
/* For the pixels screen address i,j, compute pixel address r */
/* within the dither box. Also select dither box q based on */
/* size (size = 1, 2, 4, or 8). */
/*.............................................................*/
x = (float)i/size;
y = (float)j/size;
m = (int)(size*(x - (int)x) + 0.5);
n = (int)(size*(y - (int)y) + 0.5);
q = size/2;
if(size == 8) q = 3;
r = m+n*size;
/*.............................................................*/
/* Get the Dark Pixel color, the Light Pixel components, and */
/* the pixel color errors. */
/*.............................................................*/
color = crack_rgb(rgb,&red_boost,&grn_boost,&blu_boost,
&frl,&fgl,&fbl);
/*.............................................................*/
/*Scale the pixel color error values based on dither box size */
/*.............................................................*/
red_lvl = size*size*frl;
grn_lvl = size*size*fgl;
blu_lvl = size*size*fbl;
/*.............................................................*/
/*Test the pixels red, green, and blue error values against the*/
/*thresholds in the dither box. Decide which color to use. */
/*.............................................................*/
if(dither[q][r] <= red_lvl)
color = (color & 0x1f) + (red_boost << 5); /* Boost Red */
if(dither[q][r] <= grn_lvl)
color = (color & 0xe3) + (grn_boost << 2); /* Boost Grn */
if(dither[q][r] <= blu_lvl)
color = (color & 0xfc) + blu_boost; /* Boost Blu */
/*.............................................................*/
/* Set color and draw pixel on screen. */
/*.............................................................*/
vsa_set_color(color);
vsa_set_pixel(i,j);
return;
} /*.... END draw_dithered_pixel ....*/
/*.......................... CRACK_RGB ........... 5-27-94 ....*/
/* This routine takes the 24 bit RGB color value in the 'rgb' */
/* array, quantizes it down to an 8 bit color value (3 bit red,*/
/* 3 bit green, and 2 bit blue) and returns this 8 bit */
/* 'base_color' value. It also computes the 8 bit color boost */
/* values '*red_boost', 'grn_boost', and 'blu_boost' which are */
/* used to draw dithered pixels. It also computes the color */
/* error values 'red_lvl', 'grn_lvl', and 'blu_lvl' which */
/* determine when the dither function draws with 'base_color' */
/* and when it draws with 'xxx_boost' color. */
/*.............................................................*/
int crack_rgb(unsigned char *rgb,int *red_boost,int *grn_boost,
int *blu_boost,float *red_lvl,float *grn_lvl,
float *blu_lvl)
{
int base_color,red,grn,blu;
float fred,fgrn,fblu;
fred = rgb[2]/36.6; /*36.6 = (256 shades of red)/(2^3 - 1) */
fgrn = rgb[1]/36.6; /*36.6 = (256 shades of grn)/(2^3 - 1) */
fblu = rgb[0]/85.4; /*85.4 = (256 shades of blu)/(2^2 - 1) */
red = fred;
grn = fgrn;
blu = fblu;
base_color = (red << 5)+(grn << 2)+blu; /*Dark Pixel color */
*red_lvl = fred - red;
*grn_lvl = fgrn - grn;
*blu_lvl = fblu - blu;
*red_boost = red+1; /*This is the Light Pixel color for red */
*grn_boost = grn+1; /*This is the Light Pixel color for grn */
*blu_boost = blu+1; /*This is the Light Pixel color for blu */
return base_color;
} /*.... END crack_rgb .....*/
/*....................... READ_TGA_HEADER ....... 5-17-94 ....*/
/* This routine parses through a TGA header and returns the */
/* file offset in bytes to the first byte of pixel data. */
/* It also returns image width, height, and type (type 2 is the*/
/* uncompressed 24 bit image type). */
/*.............................................................*/
unsigned long read_tga_header(int handle, int *width,
int *height, int *type,
int *orientation)
{
unsigned long offset;
unsigned char buff[18];
read(handle,buff,18);
offset = 18+buff[0];
*type = buff[2];
*width = *((unsigned *)buff + 6);
*height = *((unsigned *)buff + 7);
*orientation = buff[17];
return offset;
} /*.... END read_tga_header .....*/
/*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
/* This routine generates a 'true color' LUT. An 8 bit index */
/* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
/* 2 bits of BLUE. The 3 msbs of the 8 bit index are the RED */
/* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
/* */
/*.............................................................*/
void true_color_lut(void)
{
int i;
unsigned char color_array[768];
for(i=0;i<256;i++)
{
color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
color_array[3*i+2]= (i & 0x0003) * 21;
}
vsa_write_color_block(0,256,color_array);
return;
} /*..... End true_color_lut .....*/
void update_message(int x0,int y0,int color,char *text)
{
clear_text_area(x0,y0,51,TF_Black);
vsa_write_string(x0,y0,color,text);
vsa_set_color(color);
return;
}
void clear_text_area(int x0,int y0,int length,int color)
{
vsa_set_color(color);
vsa_move_to(x0,y0);
vsa_rect_fill(x0+length*XCharSize-1,y0+YCharSize-1);
return;
}
/*.......................... VSA_GET_INPUT .................... 6-25-94 ....*/
/* This routine reads the keyboard input and echos it to the screen until */
/* a carriage return is entered. Then the whole text string is returned */
/* via 'text'. */
/*..........................................................................*/
void vsa_get_input(char *text)
{
int i,x,y;
char key;
vsa_get_text_cursor(&x,&y);
i=0;
text[0] = 0;
key = getch();
while((key != 13) && (key != 27)) /* Do until a return */
{ /* or an ESCAPE Key is hit. */
if(key != 8)
{ /* If not a back space */
text[i] = key; /* add key entry to string. */
text[i+1] = 0;
vsa_write_string(x,y,TF_White,text);/* Echo the updated string. */
i++;
}
else
{ /* If a back space */
if(i > 0) i --; /* delete last key entry. */
text[i] = 92;
vsa_write_string(x,y,TF_White,text);/* Echo the updated string. */
text[i] = 0;
}
key = getch();
}
return;
}
void color_bar(x0,y0)
int x0,y0;
{
int i;
unsigned xx,yy,a,b;
float c;
xx = XResolution;
yy = YResolution;
/*..........................................................................*/
/* Draw outline for color bar. */
/*..........................................................................*/
vsa_set_color(15);
vsa_move_to(x0-1,y0-1);
a = .75*xx;
b = .065*yy;
vsa_rect(x0+a+1,y0+b+1);
c = (float)a/256;
for(i=0;i<256;i++)
{
vsa_set_color((unsigned char)i);
vsa_move_to(x0+(unsigned)(i*c),y0);
vsa_rect_fill(x0+(unsigned)(c+i*c),y0+b);
}
return;
}